﻿using System;
using System.Diagnostics;
using System.ComponentModel;
using System.Globalization;
using System.Collections.Generic;
using VMExplorer.Win32;

namespace VMExplorer.MemoryObjects
{
  /// <summary>
  /// The memory region that mapped loaded binaries.
  /// </summary>
  class ModuleObject : GenericMemoryObject
  {
    #region Construction

    public ModuleObject (SafeProcessHandle hProcess, MemoryAddress baseAddress, string name)
      : base (hProcess, baseAddress, name, RegionUsage.Modules)
    {
      ModulePath = string.Empty;
      ImageDosHeader = RemoteMemoryObject<Native.IMAGE_DOS_HEADER>.ReadStructure (ProcessHandle, baseAddress);
      ImageNtHeader = RemoteMemoryObject<Native.IMAGE_NT_HEADERS>.ReadStructure (ProcessHandle, baseAddress + ImageDosHeader.NewHeaderOffset);
    }

		public ModuleObject (SafeProcessHandle hProcess, LdrModule ldr)
      : base (hProcess, ldr.Inner.BaseAddress, RemoteReader.ReadStringUni (hProcess, ldr.Inner.BaseDllName.Buffer, ldr.Inner.BaseDllName.Length), RegionUsage.Modules)
    {
      ModulePath = RemoteReader.ReadStringUni (hProcess, ldr.Inner.FullDllName.Buffer, ldr.Inner.FullDllName.Length);
      TimeDateStamp = TimeZone.CurrentTimeZone.ToLocalTime (DateTime.Parse ("1/1/1970 0:0:0").AddSeconds ((double)ldr.Inner.TimeDateStamp));
      Size = ldr.Inner.SizeOfImage;

      ImageDosHeader = RemoteMemoryObject<Native.IMAGE_DOS_HEADER>.ReadStructure (hProcess, ldr.Inner.BaseAddress);
      ImageNtHeader = RemoteMemoryObject<Native.IMAGE_NT_HEADERS>.ReadStructure (hProcess, (MemoryAddress)ldr.Inner.BaseAddress + ImageDosHeader.NewHeaderOffset);
    }

    #endregion
    #region Scan rule

    public static void InstallScanRule (Scanner scan)
    {
      scan.NextRegion += delegate (object sender, Scanner.NextRegionEventArgs e)
      {
        if (e.Handled) return;

				Int16 sig = RemoteReader.ReadInt16 (e.ProcessHandle, e.Range.Start);
        if (sig == /*'MZ'*/0x5A4D)
        {
					e.MemObjects.Add (new ModuleObject (e.ProcessHandle, e.Range.Start, "Unknown module"));
          e.Handled = true;
        }
      };
    }

    #endregion
    #region Public Properties

    public string ModulePath;// { get; private set; }
    public DateTime TimeDateStamp;// { get; private set; }
    public uint Size;// { get; private set; }
    public Native.IMAGE_DOS_HEADER ImageDosHeader;// { get; private set; }
    public Native.IMAGE_NT_HEADERS ImageNtHeader;// { get; private set; }
    //private ImageSectionHeaderObject[] _sectionHeaders;

    #endregion
  };


  //[TypeConverter (typeof (ExpandableObjectConverter))]
  //class ImageNtHeader : RemoteTypeWrapper<Native.IMAGE_NT_HEADERS>
  //{
  //  public ImageNtHeader (SafeProcessHandle hProcess, MemoryAddress baseAddress)
  //    : base (hProcess, baseAddress)
  //  {
  //  }
  //  //public ImageDataDirectory DataDirectoryExport { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryExport); } }
  //  //public ImageDataDirectory DataDirectoryImport { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryImport); } }
  //  //public ImageDataDirectory DataDirectoryResource { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryResource); } }
  //  //public ImageDataDirectory DataDirectoryException { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryException); } }
  //  //public ImageDataDirectory DataDirectorySecurity { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectorySecurity); } }
  //  //public ImageDataDirectory DataDirectoryBaseReloc { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryBaseReloc); } }
  //  //public ImageDataDirectory DataDirectoryDebug { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryDebug); } }
  //  //public ImageDataDirectory DataDirectoryCopyright { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryCopyright); } }
  //  //public ImageDataDirectory DataDirectoryArchitecure { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryArchitecure); } }
  //  //public ImageDataDirectory DataDirectoryGlobalPtr { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryGlobalPtr); } }
  //  //public ImageDataDirectory DataDirectoryTLS { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryTLS); } }
  //  //public ImageDataDirectory DataDirectoryLoadConfig { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryLoadConfig); } }
  //  //public ImageDataDirectory DataDirectoryBoundImport { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryBoundImport); } }
  //  //public ImageDataDirectory DataDirectoryIAT { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryIAT); } }
  //  //public ImageDataDirectory DataDirectoryDelayImport { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryDelayImport); } }
  //  //public ImageDataDirectory DataDirectoryComDescriptor { get { return new ImageDataDirectory(Inner.OptionalHeader.DataDirectoryComDescriptor); } }
  //};



  //class ImageDataDirectoryConverter : ExpandableObjectConverter
  //{
  //  public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destType)
  //  {
  //    if (destType == typeof (string) && value is ImageDataDirectory)
  //    {
  //      ImageDataDirectory idd = (ImageDataDirectory)value;
  //      if (idd.Size == 0) return "(None)";
  //      return string.Format ("{0}, size={1}", idd.VirtualAddress, idd.Size);
  //    }
  //    return base.ConvertTo (context, culture, value, destType);
  //  }
  //}

  //[TypeConverter (typeof (ImageDataDirectoryConverter))]
  //class ImageDataDirectory : TypeWrapper<Native.IMAGE_DATA_DIRECTORY>
  //{
  //  public ImageDataDirectory (Native.IMAGE_DATA_DIRECTORY inner)
  //    : base (inner)
  //  {
  //  }

  //  public MemoryAddress VirtualAddress { get { return Inner.VirtualAddress; } }
  //  public UInt32 Size { get { return Inner.Size; } }
  //};


  //[TypeConverter (typeof (ExpandableObjectConverter))]
  //class ImageSectionHeader : RemoteTypeWrapper<Native.IMAGE_SECTION_HEADER>
  //{
  //  public ImageSectionHeader (SafeProcessHandle hProcess, MemoryAddress baseAddress)
  //    : base (hProcess, baseAddress)
  //  {
  //  }

  //  public string Name { get { return Inner.Name; } }
  //  public UInt32 VirtualSize { get { return Inner.VirtualSize; } }
  //  public UInt32 VirtualAddress { get { return Inner.VirtualAddress; } }
  //  public UInt32 SizeOfRawData { get { return Inner.SizeOfRawData; } }
  //  public UInt32 PointerToRawData { get { return Inner.PointerToRawData; } }
  //  public UInt32 PointerToRelocations { get { return Inner.PointerToRelocations; } }
  //  public UInt32 PointerToLinenumbers { get { return Inner.PointerToLinenumbers; } }
  //  public UInt16 NumberOfRelocations { get { return Inner.NumberOfRelocations; } }
  //  public UInt16 NumberOfLinenumbers { get { return Inner.NumberOfLinenumbers; } }
  //  public UInt32 Characteristics { get { return Inner.Characteristics; } }
  //};



}
